/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package phd.dupenois.changeidentifiers.algorithms.convexhull;

import java.util.Iterator;
import java.util.Vector;
import phd.dupenois.changeidentifiers.algorithms.convexhull.frames.MainFrame;
import phd.dupenois.changeidentifiers.dotpatterns.DotPattern;
import phd.dupenois.changeidentifiers.footprints.Footprint;
import phd.dupenois.changeidentifiers.footprints.algorithms.FootprintAlgorithm;
import uk.co.dupenois.geometry.Coordinate;
import uk.co.dupenois.geometry.CoordinateList;
import uk.co.dupenois.geometry.Line;

/**
 *
 * @author mpd209
 */
public class UpperAndLower extends FootprintAlgorithm {
    public static boolean DISPLAY = false;
    public static boolean PAUSE = false;

    private MainFrame frame;

    public void initialise() {
        if(DISPLAY){
            frame = new MainFrame();
            frame.setVisible(true);
        }
    }
    private boolean useDisplay(){
        return frame!=null;
    }
    private void pause() {
        if(PAUSE){
            try {
                Thread.sleep(1000);
            } catch (InterruptedException ex) {
            }
        }
    }

    public Footprint generateFootprint(DotPattern pattern) throws Exception {
        if (pattern == null) {
            return new Footprint();
        }
        if (!pattern.isFinalised()) {
//            long finaliseTime = System.currentTimeMillis();
            pattern.finalise();
//            System.out.println("[F] Pattern not finalised, took "+(System.currentTimeMillis()-finaliseTime)+"ms to finalise");
        }
//        long listTime = System.currentTimeMillis();
        CoordinateList list = pattern.getList();
//        System.out.println("[F] Getting list took "+(System.currentTimeMillis()-listTime)+"ms");

        if(useDisplay())frame.setDotPattern(pattern);
        pause();

        Footprint footprint = new Footprint();
        if (list.size() < 3) {
            return footprint;
        }
        Vector<Coordinate> xList = (Vector<Coordinate>) list.getByX().clone();
        Vector<Coordinate> lUpper = new Vector<Coordinate>();
        Vector<Coordinate> lLower = new Vector<Coordinate>();
        int xSize = xList.size();


//        long upperTime = System.currentTimeMillis();
        lUpper.add(xList.get(0));
        lUpper.add(xList.get(1));
        for (int i = 2; i < xSize; i++) {

            if (!lUpper.contains(xList.get(i))) {
                lUpper.add(xList.get(i));
                if(useDisplay())frame.setDotBeingAdded(xList.get(i));
                while (lUpper.size() > 2 && !lastThreeIsRightTurn(lUpper)) {
                    lUpper.remove(lUpper.size() - 2);
                }
                if(useDisplay() && lUpper.size()>2 )
                    frame.setCurrentUpperHull(lUpper.toArray(new Coordinate[lUpper.size()]));
            }
        }
//        System.out.println("[F] Getting upper took "+(System.currentTimeMillis()-upperTime)+"ms");


//        long lowerTime = System.currentTimeMillis();
        lLower.add(xList.lastElement());
        lLower.add(xList.get(xSize - 2));
        for (int i = xSize - 3; i >= 0; i--) {
            pause();
            if (!lLower.contains(xList.get(i))) {
                lLower.add(xList.get(i));
                if(useDisplay())frame.setDotBeingAdded(xList.get(i));
                while (lLower.size() > 2 && !lastThreeIsRightTurn(lLower)) {
                    lLower.remove(lLower.size() - 2);
                }
                if(useDisplay() && lLower.size()>2)
                    frame.setCurrentLowerHull(lLower.toArray(new Coordinate[lLower.size()]));
            }
        }

//        System.out.println("[F] Getting lower took "+(System.currentTimeMillis()-lowerTime)+"ms");

        lLower.remove(0);
        lLower.remove(lLower.size() - 1);
        lUpper.addAll(lLower);

        Iterator<Coordinate> iter = lUpper.iterator();
        Coordinate last = iter.next();
        Coordinate current;
        while (iter.hasNext()) {
            current = iter.next();
            footprint.addLine(last, current);
            last = current;
        }
        return footprint;
    }

    private boolean lastThreeIsRightTurn(Vector<Coordinate> list) {
        if (list.size() < 3) {
            throw new IllegalArgumentException("List must have at least 3 elements");
        }
        Coordinate last = list.lastElement();
        Coordinate last_1 = list.get(list.size() - 2);
        Coordinate last_2 = list.get(list.size() - 3);
        Line line = new Line(last_2, last_1, true);
        if(useDisplay())frame.setRightAngleCheck(last, last_1, last_2);
        pause();
        return line.isCoordinateRightOfLine(last);
    }
}
